home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / othergnu / ispell.zoo / tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-06  |  15.9 KB  |  742 lines

  1. /* -*- Mode:Text -*- */
  2.  
  3. /*
  4.  * tree.c - a hash style dictionary for user's personal words
  5.  *
  6.  * Pace Willisson, 1983
  7.  * Hash support added by Geoff Kuenning, 1987
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <ctype.h>
  12. #include <sys/param.h>
  13. #include "config.h"
  14. #include "ispell.h"
  15.  
  16. char *getenv();
  17. struct dent *lookup();
  18. char *upcase();
  19.  
  20. static int cantexpand = 0;    /* NZ if an expansion fails */
  21. static struct dent *htab = NULL; /* Hash table for our stuff */
  22. static int hsize = 0;        /* Space available in hash table */
  23. static int hcount = 0;        /* Number of items in hash table */
  24.  
  25. /*
  26.  * Hash table sizes.  Prime is probably a good idea, though in truth I
  27.  * whipped the algorithm up on the spot rather than looking it up, so
  28.  * who knows what's really best?  If we overflow the table, we just
  29.  * use a double-and-add-1 algorithm.
  30.  *
  31.  * The strange pattern in the table is because this table is sometimes
  32.  * used with huge dictionaries, and we want to get the table bigger fast.
  33.  * 23003 just happens to be such that the original dict.191 will fill
  34.  * the table to just under 70%.  31469 is similarly selected for dict.191
  35.  * combined with /usr/dict/words.  The other numbers are on 10000-word
  36.  * intervals starting at 30000.  (The table is still valid if MAXPCT
  37.  * is changed, but the dictionary sizes will no longer fall on neat
  38.  * boundaries).
  39.  */
  40. static int goodsizes[] = {
  41.     53, 223, 907,
  42. #if ((BIG_DICT * 100) / MAXPCT) <= 23003
  43.     23003,                /* ~16000 words */
  44. #endif
  45. #if ((BIG_DICT * 100) / MAXPCT) <= 31469
  46.     31469,                /* ~22000 words */
  47. #endif
  48. #if ((BIG_DICT * 100) / MAXPCT) <= 42859
  49.     42859,                /* ~30000 words */
  50. #endif
  51. #if ((BIG_DICT * 100) / MAXPCT) <= 57143
  52.     57143,                /* ~40000 words */
  53. #endif
  54.     71429                /* ~50000 words */
  55. };
  56.  
  57. struct dent *treeinsert();
  58. struct dent *tinsert();
  59. struct dent *treelookup();
  60. char *upcase ();
  61. char *lowcase ();
  62.  
  63. static char personaldict[MAXPATHLEN];
  64. static FILE *dictf;
  65. static newwords = 0;
  66.  
  67. extern char *index ();
  68. extern char *calloc ();
  69. extern char *malloc ();
  70. extern char *realloc ();
  71.  
  72. extern struct dent *hashtbl;
  73. extern int hashsize;
  74.  
  75. treeinit (p)
  76. char *p;
  77. {
  78.     register char *h;
  79.     char *orig;
  80.     char buf[BUFSIZ];
  81.     register struct dent *dp;
  82.  
  83.     /*
  84.     ** if p exists and begins with '/' we don't really need HOME,
  85.     ** but it's not very likely that HOME isn't set anyway.
  86.     */
  87.     orig = p;
  88.     if (p == NULL)
  89.         p = getenv (PDICTVAR);
  90.     if ((h = getenv ("HOME")) == NULL)
  91.         return;
  92.  
  93.     if (p == NULL)
  94.         sprintf(personaldict,"%s/%s",h,DEFPDICT);
  95.     else {
  96.         if (*p == '/')
  97.             strcpy(personaldict,p);
  98.         else {
  99.             /*
  100.             ** The user gave us a relative pathname.  How we
  101.             ** interpret it depends on how it was given:
  102.             **
  103.             ** -p switch:  as-is first, then $HOME/name
  104.             ** PDICTVAR:   $HOME/name first, then as-is
  105.             **/
  106.             if (orig == NULL)
  107.                 sprintf (personaldict, "%s/%s", h, p);
  108.             else            /* -p switch */
  109.                 strcpy (personaldict, p);
  110.         }
  111.     }
  112.  
  113.     if ((dictf = fopen (personaldict, "r")) == NULL) {
  114.         /* The file doesn't exist. */
  115.         if (p != NULL) {
  116.             /* If pathname is relative, try another place */
  117.             if (*p != '/') {
  118.                 if (orig == NULL)
  119.                     strcpy (personaldict, p);
  120.                 else            /* -p switch */
  121.                     sprintf (personaldict, "%s/%s", h, p);
  122.                 dictf = fopen (personaldict, "r");
  123.             }
  124.             if (dictf == NULL) {
  125.                 (void) fprintf (stderr, "Couldn't open ");
  126.                 perror (p);
  127.                 if (*p != '/') {
  128.                     /*
  129.                     ** Restore the preferred default, so
  130.                     ** that output will go th the right
  131.                     ** place.
  132.                     */
  133.                     if (orig == NULL)
  134.                         sprintf (personaldict,
  135.                           "%s/%s", h, p);
  136.                     else            /* -p switch */
  137.                         strcpy (personaldict, p);
  138.                 }
  139.             }
  140.         }
  141.         /* If the name wasn't specified explicitly, we don't object */
  142.         return;
  143.     }
  144.  
  145.     while (fgets (buf, sizeof buf, dictf) != NULL) {
  146.         int len = strlen (buf) - 1;
  147.  
  148.         if (buf [ len ] == '\n')
  149.             buf [ len-- ] = '\0';
  150.         if ((h = index (buf, '/')) != NULL)
  151.             *h++ = '\0';
  152.         dp = treeinsert (buf, 1);
  153.         if (h != NULL) {
  154.             while (*h != '\0'  &&  *h != '\n') {
  155.                 switch (*h++) {
  156.                 case 'D':
  157.                 case 'd':
  158.                     dp->d_flag = 1;
  159.                     break;
  160.                 case 'G':
  161.                 case 'g':
  162.                     dp->g_flag = 1;
  163.                     break;
  164.                 case 'H':
  165.                 case 'h':
  166.                     dp->h_flag = 1;
  167.                     break;
  168.                 case 'J':
  169.                 case 'j':
  170.                     dp->j_flag = 1;
  171.                     break;
  172.                 case 'M':
  173.                 case 'm':
  174.                     dp->m_flag = 1;
  175.                     break;
  176.                 case 'N':
  177.                 case 'n':
  178.                     dp->n_flag = 1;
  179.                     break;
  180.                 case 'P':
  181.                 case 'p':
  182.                     dp->p_flag = 1;
  183.                     break;
  184.                 case 'R':
  185.                 case 'r':
  186.                     dp->r_flag = 1;
  187.                     break;
  188.                 case 'S':
  189.                 case 's':
  190.                     dp->s_flag = 1;
  191.                     break;
  192.                 case 'T':
  193.                 case 't':
  194.                     dp->t_flag = 1;
  195.                     break;
  196.                 case 'V':
  197.                 case 'v':
  198.                     dp->v_flag = 1;
  199.                     break;
  200.                 case 'X':
  201.                 case 'x':
  202.                     dp->x_flag = 1;
  203.                     break;
  204.                 case 'Y':
  205.                 case 'y':
  206.                     dp->y_flag = 1;
  207.                     break;
  208.                 case 'Z':
  209.                 case 'z':
  210.                     dp->z_flag = 1;
  211.                     break;
  212.                 default:
  213.                     fprintf (stderr,
  214.                       "Illegal flag in personal dictionary - %c (word %s)\n",
  215.                       h[-1], buf);
  216.                     break;
  217.                 }
  218.                 /* Accept old-format dicts with extra slashes */
  219.                 if (*h == '/')
  220.                     h++;
  221.             }
  222.         }
  223.     }
  224.  
  225.     fclose (dictf);
  226.  
  227.     newwords = 0;
  228.  
  229.     if (!lflag && !aflag && access (personaldict, 2) < 0)
  230.         fprintf (stderr,
  231.             "Warning: Cannot update personal dictionary (%s)\r\n",
  232.             personaldict);
  233. }
  234.  
  235. struct dent *
  236. treeinsert (word, keep)
  237. char *word;
  238. {
  239.     register int i;
  240.     register struct dent *dp;
  241.     struct dent *olddp;
  242.     struct dent *oldhtab;
  243.     int oldhsize;
  244.     char nword[BUFSIZ];
  245. #ifdef CAPITALIZE
  246.     register char *cp;
  247.     char *saveword;
  248.     int capspace;
  249. #endif
  250.  
  251.     strcpy (nword, word);
  252.     upcase (nword);
  253.     if ((dp = lookup (nword, strlen (nword), 0)) != NULL)
  254.         dp->keep = keep;
  255.     /*
  256.      * Expand hash table when it is MAXPCT % full.
  257.      */
  258.     else if (!cantexpand  &&  (hcount * 100) / MAXPCT >= hsize) {
  259.         oldhsize = hsize;
  260.         oldhtab = htab;
  261.         for (i = 0;  i < sizeof goodsizes / sizeof (goodsizes[0]);  i++)
  262.             if (goodsizes[i] > hsize)
  263.                 break;
  264.         if (i >= sizeof goodsizes / sizeof goodsizes[0])
  265.             hsize += hsize + 1;
  266.         else
  267.             hsize = goodsizes[i];
  268.         htab = (struct dent *) calloc (hsize, sizeof (struct dent));
  269.         if (htab == NULL) {
  270.             (void) fprintf (stderr,
  271.                 "Ran out of space for personal dictionary\n");
  272.             /*
  273.              * Try to continue anyway, since our overflow
  274.              * algorithm can handle an overfull (100%+) table,
  275.              * and the malloc very likely failed because we
  276.              * already have such a huge table, so small mallocs
  277.              * for overflow entries will still work.
  278.              */
  279.             if (oldhtab == NULL)
  280.                 exit (1);    /* No old table, can't go on */
  281.             (void) fprintf (stderr,
  282.                 "Continuing anyway (with reduced performance).\n");
  283.             cantexpand = 1;        /* Suppress further messages */
  284.             hsize = oldhsize;    /* Put this back how the were */
  285.             htab = oldhtab;        /* ... */
  286.             newwords = 1;        /* And pretend it worked */
  287.             return tinsert (nword, (struct dent *) NULL, keep);
  288.         }
  289.         /*
  290.          * Re-insert old entries into new table
  291.          */
  292.         for (i = 0;  i < oldhsize;  i++) {
  293.             dp = &oldhtab[i];
  294.             if (oldhtab[i].used) {
  295.                 tinsert ((char *) NULL, dp, 0);
  296.                 dp = dp->next;
  297.                 while (dp != NULL) {
  298.                     tinsert ((char *) NULL, dp, 0);
  299.                     olddp = dp;
  300.                     dp = dp->next;
  301.                     free ((char *) olddp);
  302.                 }
  303.             }
  304.         }
  305.         if (oldhtab != NULL)
  306.             free ((char *) oldhtab);
  307.         dp = NULL;        /* This will force the insert below */
  308.     }
  309.     newwords |= keep;
  310.     if (dp == NULL)
  311.         dp = tinsert (nword, (struct dent *) NULL, keep);
  312. #ifdef CAPITALIZE
  313.     if (dp == NULL)
  314.         return NULL;
  315.     /*
  316.     ** Figure out the capitalization rules from the
  317.     ** capitalization of the sample entry.  If the sample is
  318.     ** all caps, we don't change the existing flags, since
  319.     ** all-caps gives us no information.  Tinsert initializes
  320.     ** new entries with "allcaps" set, so if the word is truly
  321.     ** required to appear in capitals, the correct result
  322.     ** will be achieved.
  323.     */
  324.     for (cp = word;  *cp;  cp++) {
  325.         if (mylower (*cp))
  326.             break;
  327.     }
  328.     if (*cp) {
  329.         /*
  330.         ** Sample entry has at least some lowercase.  See if
  331.         ** the case is mixed.
  332.         */
  333.         for (cp = word;  *cp;  cp++) {
  334.             if (myupper (*cp))
  335.                 break;
  336.         }
  337.         if (*cp == '\0'  &&  !dp->followcase) {
  338.             /*
  339.             ** Sample entry is all lowercase, and word is not
  340.             ** followcase.  Clear all of the capitalization flags.
  341.             */
  342.             dp->allcaps = 0;
  343.             dp->capitalize = 0;
  344.             if (keep) {
  345.                 dp->k_allcaps = 0;
  346.                 dp->k_capitalize = 0;
  347.                 dp->k_followcase = 0;
  348.             }
  349.         }
  350.         else {
  351.             /*
  352.             ** The sample entry is mixed case (or all-lower and the
  353.             ** entry is already followcase).  If it's simply
  354.             ** capitalized, set the capitalize flag and that's that.
  355.             */
  356.             for (cp = word + 1;  *cp  &&  !myupper (*cp);  )
  357.                 cp++;
  358.             if (*cp == 0  &&  myupper (*word)) {
  359.                 dp->allcaps = 0;
  360.                 dp->capitalize = 1;
  361.                 if (keep) {
  362.                     dp->k_allcaps = 0;
  363.                     dp->k_capitalize = 1;
  364.                 }
  365.             }
  366.             else {
  367.                 /*
  368.                 ** The sample entry is followcase.  Make the
  369.                 ** dictionary entry followcase if necessary.
  370.                 */
  371.                 if (!dp->followcase) {
  372.                     dp->followcase = 1;
  373.                     if (keep)
  374.                         dp->k_followcase = 1;
  375.                     capspace = 2 * (strlen (dp->word) + 2);
  376.                     if (dp->word >= hashstrings
  377.                       &&  dp->word <=
  378.                         hashstrings
  379.                          + hashheader.stringsize) {
  380.                         cp = dp->word;
  381.                         dp->word = malloc (capspace);
  382.                         if (dp->word)
  383.                             strcpy (dp->word, cp);
  384.                     }
  385.                     else
  386.                         dp->word = realloc (dp->word,
  387.                                     capspace);
  388.                     if (dp->word == NULL) {
  389.                         fprintf (stderr,
  390.                           "Ran out of space for personal dictionary\n");
  391.                         exit (1);
  392.                     }
  393.                     cp = dp->word + strlen (dp->word) + 1;
  394.                     if (dp->capitalize  ||  dp->allcaps)
  395.                         *cp++ = 0;
  396.                     else {
  397.                         *cp++ = 1;
  398.                         strcpy (cp + 1, dp->word);
  399.                         lowcase (cp + 1);
  400.                     }
  401.                     *cp = dp->keep ? '+' : '-';
  402.                 }
  403.                 dp->allcaps = 0;
  404.                 if (keep)
  405.                     dp->k_allcaps = 0;
  406.                 cp = dp->word + strlen (dp->word) + 1;
  407.                 /* Add a new capitalization */
  408.                 (*cp)++;
  409.                 capspace = (cp - dp->word + 1)
  410.                         * ((*cp & 0xFF) + 1);
  411.                 if (dp->word >= hashstrings
  412.                   &&  dp->word <=
  413.                     hashstrings + hashheader.stringsize) {
  414.                     saveword = dp->word;
  415.                     dp->word = malloc (capspace);
  416.                     if (dp->word) {
  417.                         cp = dp->word;
  418.                         while (--capspace >= 0)
  419.                             *cp++ = *saveword++;
  420.                     }
  421.                 }
  422.                 else
  423.                     dp->word = realloc (dp->word, capspace);
  424.                 if (dp->word == NULL) {
  425.                     fprintf (stderr,
  426.                       "Ran out of space for personal dictionary\n");
  427.                     exit (1);
  428.                 }
  429.                 cp = dp->word + strlen (dp->word) + 1;
  430.                 cp +=
  431.                   ((*cp & 0xFF) - 1) * (cp - dp->word + 1) + 1;
  432.                 *cp++ = keep ? '+' : '-';
  433.                 strcpy (cp, word);
  434.             }
  435.         }
  436.     }
  437. #endif
  438.     return dp;
  439. }
  440.  
  441. static
  442. struct dent *
  443. tinsert (word, proto, keep)
  444. char *word;            /* One of word/proto must be null */
  445. struct dent *proto;
  446. {
  447.     register int hcode;
  448.     register struct dent *hp; /* Next trial entry in hash table */
  449.     register struct dent *php;    /* Previous value of hp, for chaining */
  450.     register char *cp;
  451.  
  452.     if (word == NULL)
  453.         word = proto->word;
  454.     hcode = hash (word, strlen (word), hsize);
  455.     php = NULL;
  456.     hp = &htab[hcode];
  457.     if (hp->used) {
  458.         while (hp != NULL) {
  459.             if (strcmp (word, hp->word) == 0) {
  460.                 if (keep)
  461.                     hp->keep = 1;
  462.                 return hp;
  463.             }
  464.             php = hp;
  465.             hp = hp->next;
  466.         }
  467.         hp = (struct dent *) calloc (1, sizeof (struct dent));
  468.         if (hp == NULL) {
  469.             (void) fprintf (stderr,
  470.                 "Ran out of space for personal dictionary\n");
  471.             exit (1);
  472.         }
  473.     }
  474.     if (proto != NULL) {
  475.         *hp = *proto;
  476.         if (php != NULL)
  477.             php->next = hp;
  478.         hp->next = NULL;
  479.         return &htab[hcode];
  480.     } else {
  481.         if (php != NULL)
  482.             php->next = hp;
  483.         hp->word = (char *) malloc (strlen (word) + 1);
  484.         if (hp->word == NULL) {
  485.             (void) fprintf (stderr,
  486.                 "Ran out of space for personal dictionary\n");
  487.             exit (1);
  488.         }
  489.         strcpy (hp->word, word);
  490.         hp->used = 1;
  491.         hp->next = NULL;
  492.         hp->d_flag = 0;
  493.         hp->g_flag = 0;
  494.         hp->h_flag = 0;
  495.         hp->j_flag = 0;
  496.         hp->m_flag = 0;
  497.         hp->n_flag = 0;
  498.         hp->p_flag = 0;
  499.         hp->r_flag = 0;
  500.         hp->s_flag = 0;
  501.         hp->t_flag = 0;
  502.         hp->v_flag = 0;
  503.         hp->x_flag = 0;
  504.         hp->y_flag = 0;
  505.         hp->z_flag = 0;
  506. #ifdef CAPITALIZE
  507.         hp->allcaps = 1;        /* Assume word is all-caps */
  508.         hp->k_allcaps = 1;
  509.         hp->capitalize = 0;
  510.         hp->k_capitalize = 0;
  511.         hp->followcase = 0;
  512.         hp->k_followcase = 0;
  513. #endif
  514.         hp->keep = keep;
  515.         hcount++;
  516.         return (hp);
  517.     }
  518. }
  519.  
  520. struct dent *
  521. treelookup (word)
  522. char *word;
  523. {
  524.     register int hcode;
  525.     register struct dent *hp;
  526.     char nword[BUFSIZ];
  527.  
  528.     if (hsize <= 0)
  529.         return NULL;
  530.     strcpy (nword, word);
  531.     hcode = hash (nword, strlen (nword), hsize);
  532.     hp = &htab[hcode];
  533.     while (hp != NULL  &&  hp->used) {
  534.         if (strcmp (nword, hp->word) == 0)
  535.             break;
  536.         hp = hp->next;
  537.     }
  538.     if (hp != NULL  &&  hp->used)
  539.         return hp;
  540.     else
  541.         return NULL;
  542. }
  543.  
  544. treeoutput ()
  545. {
  546.     register struct dent *cent;    /* Current entry */
  547.     register struct dent *lent;    /* Linked entry */
  548. #ifdef SORTPERSONAL
  549.     register struct dent *lowent;    /* Alphabetically lowest entry */
  550.     struct dent *firstent;        /* First entry to be kept */
  551. #endif
  552.     if (newwords == 0)
  553.         return;
  554.  
  555.     if ((dictf = fopen (personaldict, "w")) == NULL) {
  556.         fprintf (stderr, "Can't create %s\r\n", personaldict);
  557.         return;
  558.     }
  559.  
  560. #ifdef SORTPERSONAL
  561.     if (hcount >= SORTPERSONAL) {
  562. #endif
  563.         for (cent = htab;  cent - htab < hsize;  cent++) {
  564.             for (lent = cent;  lent != NULL;  lent = lent->next) {
  565.                 if (lent->used  &&  lent->keep)
  566.                     toutent (lent);
  567.             }
  568.         }
  569.         for (cent = hashtbl, lent = hashtbl + hashsize;
  570.             cent < lent;
  571.             cent++) {
  572.             if (cent->used  &&  cent->keep)
  573.                 toutent (cent);
  574.         }
  575. #ifdef SORTPERSONAL
  576.         return;
  577.     }
  578.     /*
  579.     ** Produce dictionary in sorted order.  We use a selection sort,
  580.     ** which is moderately inefficient, but easy to do in our hash table.
  581.     ** We start by linking all "keep" entries together to save time.
  582.     */
  583.     for (lowent = NULL, cent = hashtbl, lent = hashtbl + hashsize;
  584.         cent < lent;
  585.         cent++) {
  586.         if (cent->keep  &&  cent->used) {
  587.             cent->next = lowent;
  588.             lowent = cent;
  589.         }
  590.     }
  591.     firstent = lowent;
  592.     for (cent = htab;  cent - htab < hsize;  cent++) {
  593.         for (lent = cent;  lent != NULL;  lent = lowent) {
  594.             lowent = lent->next;
  595.             if (lent->keep  &&  lent->used) {
  596.                 lent->next = firstent;
  597.                 firstent = lent;
  598.             }
  599.         }
  600.     }
  601.     /* Now do the sort. */
  602.     while (1) {
  603.         lowent = NULL;
  604.         for (cent = firstent;  cent != NULL;  cent = cent->next) {
  605.             if (cent->used  &&  cent->keep) {
  606.                 if (lowent != NULL) {
  607.                     if (casecmp (cent->word,
  608.                             lowent->word) < 0)
  609.                         lowent = cent;
  610.                 }
  611.                 else
  612.                     lowent = cent;
  613.             }
  614.         }
  615.         if (lowent == NULL)
  616.             break;
  617.         else {
  618.             toutent (lowent);
  619.             lowent->used = 0;
  620.         }
  621.     }
  622. #endif
  623.  
  624.     newwords = 0;
  625.  
  626.     fclose (dictf);
  627. }
  628.  
  629. static int hasslash;
  630.  
  631. static
  632. toutent (cent)
  633. register struct dent *cent;
  634. {
  635. #ifdef CAPITALIZE
  636.     register char *cp;
  637.     int len;
  638.     register int wcount;
  639.  
  640.     if (cent->k_followcase) {
  641.         if (cent->k_capitalize) {
  642.             lowcase (cent->word);
  643.             if (mylower (cent->word[0]))
  644.                 cent->word[0] = toupper (cent->word[0]);
  645.             toutword (cent->word, cent);
  646.         }
  647.         len = strlen (cent->word) + 1;
  648.         cp = cent->word + len;
  649.         wcount = *cp++ & 0xFF;
  650.         while (--wcount >= 0) {
  651.             if (*cp++ == '+')
  652.                 toutword (cp, cent);
  653.             cp += len;
  654.         }
  655.     }
  656.     else {
  657.         if (!cent->k_allcaps)
  658.             lowcase (cent->word);
  659.         if (cent->k_capitalize  &&  mylower (cent->word[0]))
  660.             cent->word[0] = toupper (cent->word[0]);
  661.         toutword (cent->word, cent);
  662.     }
  663. #else
  664.     toutword (cent->word, cent);
  665. #endif
  666. }
  667.         
  668. static
  669. toutword (word, cent)
  670. char *word;
  671. register struct dent *cent;
  672. {
  673.     hasslash = 0;
  674.     fprintf (dictf, "%s", word);
  675.     if (cent->d_flag)
  676.         flagout ('D');
  677.     if (cent->g_flag)
  678.         flagout ('G');
  679.     if (cent->h_flag)
  680.         flagout ('H');
  681.     if (cent->j_flag)
  682.         flagout ('J');
  683.     if (cent->m_flag)
  684.         flagout ('M');
  685.     if (cent->n_flag)
  686.         flagout ('N');
  687.     if (cent->p_flag)
  688.         flagout ('P');
  689.     if (cent->r_flag)
  690.         flagout ('R');
  691.     if (cent->s_flag)
  692.         flagout ('S');
  693.     if (cent->t_flag)
  694.         flagout ('T');
  695.     if (cent->v_flag)
  696.         flagout ('V');
  697.     if (cent->x_flag)
  698.         flagout ('X');
  699.     if (cent->y_flag)
  700.         flagout ('Y');
  701.     if (cent->z_flag)
  702.         flagout ('Z');
  703.     fprintf (dictf, "\n");
  704. }
  705.  
  706. static
  707. flagout (flag)
  708. {
  709.     if (!hasslash)
  710.         putc ('/', dictf);
  711.     hasslash = 1;
  712.     putc (flag, dictf);
  713. }
  714.  
  715. char *
  716. upcase (s)
  717. register char *s;
  718. {
  719.     register char *os = s;
  720.  
  721.     while (*s) {
  722.         if (mylower (*s))
  723.             *s = toupper (*s);
  724.         s++;
  725.     }
  726.     return (os);
  727. }
  728.  
  729. char *
  730. lowcase (s)
  731. register char *s;
  732. {
  733.     register char *os = s;
  734.  
  735.     while (*s) {
  736.         if (myupper (*s))
  737.             *s = tolower (*s);
  738.         s++;
  739.     }
  740.     return (os);
  741. }
  742.